import { Point2 } from "../src/point/Point2";
import { Vector2 } from "../src/vector/Vector2";
import { TestBase } from "./TestBase";
import { Precision } from "../src/Precision";

export class TestPoint2 extends TestBase {
    public async runAllTests() {
        console.log('开始运行 Point2 测试...');

        this.testConstruction();
        this.testEquality();
        this.testDistance();
        this.testVectorOperations();
        this.testMovement();
        this.testClone();

        console.log('Point2 测试完成！');
    }

    /**
     * @description 测试点的构造
     */
    private testConstruction() {
        console.log('测试点的构造...');

        // 测试默认构造
        const p1 = new Point2();
        this.assert(p1.x === 0 && p1.y === 0, '默认构造应该创建原点');

        // 测试带参数构造
        const p2 = new Point2(3, 4);
        this.assert(p2.x === 3 && p2.y === 4, '带参数构造应该正确设置坐标');

        // 测试复制构造
        const p3 = new Point2(p2.x, p2.y);
        this.assert(p3.equals(p2), '复制构造应该创建相同的点');

        console.log('✓ 点的构造测试通过');
    }

    /**
     * @description 测试点的相等性
     */
    private testEquality() {
        console.log('测试点的相等性...');

        const p1 = new Point2(1, 2);
        const p2 = new Point2(1, 2);
        const p3 = new Point2(1, 2.000001);
        const p4 = new Point2(1.1, 2);

        // 测试完全相等
        this.assert(p1.equals(p2), '相同坐标的点应该相等');

        // 测试近似相等（考虑精度）
        this.assert(p1.equals(p3, 0.001), '在误差范围内的点应该相等');

        // 测试不相等
        this.assert(!p1.equals(p4), '不同坐标的点不应该相等');

        console.log('✓ 点的相等性测试通过');
    }

    /**
     * @description 测试点之间的距离计算
     */
    private testDistance() {
        console.log('测试点的距离计算...');

        const p1 = new Point2(0, 0);
        const p2 = new Point2(3, 4);
        const p3 = new Point2(1, 1);

        // 测试两点之间的距离
        this.assert(Math.abs(p1.distance(p2) - 5) < Precision.EPSILON5, '距离计算错误');

        // 测试点到原点的距离
        this.assert(Math.abs(p3.distance(p1) - Math.sqrt(2)) < Precision.EPSILON5, '到原点距离计算错误');

        // 测试点到自身的距离
        this.assert(p1.distance(p1) < Precision.EPSILON5, '点到自身的距离应该为0');

        console.log('✓ 点的距离计算测试通过');
    }

    /**
     * @description 测试点的向量操作
     */
    private testVectorOperations() {
        console.log('测试点的向量操作...');

        const p1 = new Point2(1, 1);
        const p2 = new Point2(4, 5);

        // 测试向量生成
        const vec = p1.vectorTo(p2);
        this.assert(vec.x === 3 && vec.y === 4, '向量计算错误');

        // 测试向量长度
        this.assert(Math.abs(vec.length() - 5) < Precision.EPSILON5, '向量长度计算错误');

        // 测试向量方向
        const angle = Math.atan2(vec.y, vec.x);
        this.assert(Math.abs(angle - Math.atan2(4, 3)) < Precision.EPSILON5, '向量方向计算错误');

        console.log('✓ 点的向量操作测试通过');
    }

    /**
     * @description 测试点的移动操作
     */
    private testMovement() {
        console.log('测试点的移动操作...');

        const p1 = new Point2(1, 1);
        const vec = new Vector2(2, 3);

        // 测试按向量移动
        const p2 = p1.moveBy(vec);
        this.assert(p2.x === 3 && p2.y === 4, '点的移动计算错误');

        // 测试移动不影响原点
        this.assert(p1.x === 1 && p1.y === 1, '原点不应被移动操作改变');

        // 测试零向量移动
        const zeroVec = new Vector2(0, 0);
        const p3 = p1.moveBy(zeroVec);
        this.assert(p3.equals(p1), '零向量移动应返回相同位置');

        console.log('✓ 点的移动操作测试通过');
    }

    /**
     * @description 测试点的克隆操作
     */
    private testClone() {
        console.log('测试点的克隆操作...');

        const p1 = new Point2(3, 4);
        const p2 = p1.clone();

        // 测试克隆点的值相等
        this.assert(p2.equals(p1), '克隆点应该与原点相等');

        // 测试克隆点是独立的
        p2.x = 5;
        this.assert(p1.x === 3, '修改克隆点不应影响原点');

        // 测试特殊值的克隆
        const specialPoint = new Point2(Number.MAX_VALUE, Number.MIN_VALUE);
        const clonedSpecial = specialPoint.clone();
        this.assert(clonedSpecial.equals(specialPoint), '特殊值克隆应该保持精确');

        console.log('✓ 点的克隆操作测试通过');
    }

    /**
     * @description 测试边界情况
     */
    private testEdgeCases() {
        console.log('测试边界情况...');

        // 测试极大值
        const p1 = new Point2(Number.MAX_VALUE, Number.MAX_VALUE);
        this.assert(p1.x === Number.MAX_VALUE && p1.y === Number.MAX_VALUE, '极大值处理错误');

        // 测试极小值
        const p2 = new Point2(Number.MIN_VALUE, Number.MIN_VALUE);
        this.assert(p2.x === Number.MIN_VALUE && p2.y === Number.MIN_VALUE, '极小值处理错误');

        // 测试NaN
        const p3 = new Point2(NaN, NaN);
        this.assert(isNaN(p3.x) && isNaN(p3.y), 'NaN处理错误');

        // 测试Infinity
        const p4 = new Point2(Infinity, -Infinity);
        this.assert(p4.x === Infinity && p4.y === -Infinity, 'Infinity处理错误');

        console.log('✓ 边界情况测试通过');
    }
}